#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/epoll.h>

const static int MAX_EVENTS = 10;

int set_nonblocking(int fd) 
{
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        flags = 0;
    }
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

int main()
{
    int serverfd = socket(AF_INET, SOCK_STREAM, 0);
    if (serverfd < 0) {
        perror("socket failed");
        return -1;
    }

    int opt = 1;
    int n = setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if (n < 0) {
        perror("setsockopt failed");
        close(serverfd);
        return -2;
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8080);

    n = bind(serverfd, (struct sockaddr*)&addr, sizeof(addr));
    if (n < 0) {
        perror("bind error");
        close(serverfd);
        return -3;
    }

    n = listen(serverfd, 8);
    if (n < 0) {
        perror("listen error");
        close(serverfd);
        return -4;
    }

    // 0. 设置非阻塞
    set_nonblocking(serverfd);

    // 1. 获取 epoll 实例
    int epollfd = epoll_create1(EPOLL_CLOEXEC);
    if (epollfd < 0) {
        perror("epoll create1 failed");
        close(serverfd);
        return -5;
    }

    // 2. 将监听套接字加入 epoll
    struct epoll_event ev;
    ev.data.fd = serverfd;
    ev.events = EPOLLIN | EPOLLET; // 边缘触发

    // ev.events = EPOLLIN; // 水平触发

    n = epoll_ctl(epollfd, EPOLL_CTL_ADD, serverfd, &ev);
    if (n < 0) {
        perror("epoll tcl failed");
        close(epollfd);
        close(serverfd);
        return -6;
    }

    struct epoll_event events[MAX_EVENTS];
    while (1) {
        // 3. 等待事件
        int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if (nfds < 0) {
            perror("epoll wait failed");
            break;
        }

        // 4. 处理每个就绪事件
        for (int i = 0; i < nfds; i++) {
            // 4.1 新连接
            if (events[i].data.fd == serverfd) {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                
                // 循环调用 accept
                while (1) {
                    memset(&peer, 0, sizeof(peer));

                    int clientfd = accept(serverfd, (struct sockaddr*)&peer, &len);
                    if (clientfd < 0) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                            // 所有连接已经 accept
                            break;
                        }
                        else {
                            perror("accept failed");
                            break;
                        }
                    }

                    // 设置为非阻塞
                    set_nonblocking(clientfd);

                    // 加入 epoll
                    struct epoll_event new_ev;
                    new_ev.data.fd = clientfd;
                    new_ev.events = EPOLLIN | EPOLLET; // 边缘触发

                    // new_ev.events = EPOLLIN; // 水平触发

                    int n = epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &new_ev);
                    if (n < 0) {
                        perror("epoll ctl failed");
                        close(clientfd); // 关闭文件描述符，避免资源泄露
                    }
                }
            }
            // 4.2 客户端数据就绪
            else {
                int clientfd = events[i].data.fd;
                char buffer[128] = {0};

                // 循环读取
                while (1) {
                    int cnt = recv(clientfd, buffer, 128, 0);
                    if (cnt < 0) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                            // 数据已读完
                            break;
                        }
                        else {
                            perror("recv failed");
                            close(clientfd);
                            epoll_ctl(epollfd, EPOLL_CTL_DEL, clientfd, NULL);
                            break;
                        }
                    }
                    else if (cnt == 0) {
                        // 对端关闭
                        close(clientfd);
                        epoll_ctl(epollfd, EPOLL_CTL_DEL, clientfd, NULL);
                    }
                    else {
                        buffer[cnt] = 0;
                        printf("clientfd: %d, count: %d, buffer: %s\n", clientfd, cnt, buffer);

                        send(clientfd, buffer, cnt, 0);
                    }
                }
            }
        }
    }

    close(epollfd);
    close(serverfd);

    return 0;
}


// #include <stdio.h>
// #include <sys/types.h>
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>
// #include <string.h>
// #include <unistd.h>
// #include <sys/epoll.h>

// const static int MAX_EVENTS = 8;

// int main()
// {
//     int serverfd = socket(AF_INET, SOCK_STREAM, 0);
//     if (serverfd < 0) {
//         perror("socket failed");
//         return -1;
//     }

//     int opt = 1;
//     int n = setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
//     if (n < 0) {
//         perror("setsockopt failed");
//         close(serverfd);
//         return -2;
//     }

//     // 3. 绑定
//     struct sockaddr_in addr;
//     memset(&addr, 0, sizeof(addr));
//     addr.sin_family = AF_INET;
//     // addr.sin_addr.s_addr = INADDR_ANY;
//     addr.sin_addr.s_addr = inet_addr("0.0.0.0");
//     addr.sin_port = htons(8080);

//     n = bind(serverfd, (struct sockaddr*)&addr, sizeof(addr));
//     if (n < 0) {
//         perror("bind failed");
//         close(serverfd);
//         return -3;
//     }

//     // 4. 监听
//     n = listen(serverfd, 9); 
//     // listen 的第二个参数：保存完成三次握手但未被 accept 的连接的队列大小
//     if (n < 0) {
//         perror("listen failed");
//         close(serverfd);
//         return -4;
//     }

//     // 5. 创建 epoll 实例
//     int epollfd = epoll_create1(EPOLL_CLOEXEC);
//     if (epollfd < 0) {
//         perror("epoll create1 failed");
//         close(serverfd);
//         return -5;
//     }

//     // 6. 将监听套接字加入 epoll
//     struct epoll_event ev;
//     struct epoll_event events[MAX_EVENTS];
//     ev.events = EPOLLIN; // LT 模式
//     ev.data.fd = serverfd;

//     n = epoll_ctl(epollfd, EPOLL_CTL_ADD, serverfd, &ev);
//     if (n < 0) {
//         perror("epoll ctl failed");
//         close(epollfd);
//         close(serverfd);
//         return -6;
//     }

//     while (1) {
//         // 7. 等待事件
//         int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
//         if (nfds < 0) {
//             perror("epoll wait failed");
//             break;
//         }

//         // 8. 处理每个就绪事件
//         for (int i = 0; i < nfds; i++) {
//             if (events[i].data.fd == serverfd) {
//                 // 8.1 新连接（LT 模式下一次 accept 即可）
//                 struct sockaddr_in peer;
//                 memset(&peer, 0, sizeof(peer));
//                 socklen_t len = sizeof(peer);
//                 int clientfd = accept(serverfd, (struct sockaddr*)&peer, &len);
//                 if (clientfd < 0) {
//                     perror("accept failed");
//                     continue;
//                 }

//                 // 加入 epoll
//                 ev.events = EPOLLIN;
//                 ev.data.fd = clientfd;
//                 int n = epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &ev);
//                 if (n < 0) {
//                     perror("epoll ctl failed");
//                     close(clientfd);
//                 }
//             }
//             else {
//                 // 8.2 客户端数据就绪（LT 模式）
//                 int clientfd = events[i].data.fd;
//                 char buffer[128] = {0};
//                 int count = recv(clientfd, buffer, 128, 0);
//                 if (count < 0) {
//                     perror("recv failed");
//                     close(clientfd);
//                     epoll_ctl(epollfd, EPOLL_CTL_DEL, clientfd, NULL);
//                 }
//                 else if (count == 0) {
//                     // 对端关闭
//                     close(clientfd);
//                     epoll_ctl(epollfd, EPOLL_CTL_DEL, clientfd, NULL);
//                 }
//                 else {
//                     buffer[count] = 0;
//                     printf("clientfd: %d, count: %d, buffer: %s\n", clientfd, count, buffer);

//                     send(clientfd, buffer, count, 0);
//                 }
//             }
//         }
//     }

//     close(epollfd);
//     close(serverfd);

//     return 0;
// }